using Identity.Application.Contracts.Common;
using Identity.Application.Contracts.Services;
using Identity.Domain.Aggregates;
using Identity.Infrastructure.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Identity.Infrastructure.Persistence.IdentityService;

public class RoleService : IRoleService
{
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly ApplicationDbContext _context;

    public RoleService(RoleManager<ApplicationRole> roleManager, ApplicationDbContext context)
    {
        _roleManager = roleManager;
        _context = context;
    }

    public async Task<bool> RoleExistsAsync(Guid roleId)
    {
        var role = await _roleManager.FindByIdAsync(roleId.ToString());
        if (role == null) return false;

        return true;
    }

    public async Task<bool> RoleExistsByNameAsync(string roleName)
    {

        return await _roleManager.RoleExistsAsync(roleName);
    }



    public async Task<CreateRoleResult> CreateRoleAsync(Guid roleId, string roleCode, string roleName, string? description, bool status)
    {
        var role = new ApplicationRole { Id = roleId, Name = roleCode, NormalizedName = roleName, Description = description, Status = status };
        var result = await _roleManager.CreateAsync(role);
        if (!result.Succeeded)
            return CreateRoleResult.Failed(result.Errors.Select(e => e.Description));
        return CreateRoleResult.Success();
    }

    public async Task<Role?> GetRoleByIdAsync(Guid roleId)
    {
        var result = await _context.Roles
            .Include(rp => rp.RolePermissions)
            .FirstOrDefaultAsync(r => r.Id == roleId);

        if (result == null) return null;

        // RolePermissions 只需要 ID，不要把 EF Role、Permission 实体带进去
        var permissionIds = result.RolePermissions
            .Select(rp => rp.PermissionId)
            .ToList();

        var role = Role.LoadFromPersistence(
            result.Id,
            result.Name!,
            result.NormalizedName,
            permissionIds,  // 只传 ID
            result.Description,
            result.Status
        );
        return role;
    }

    public async Task<RoleDto?> GetRoleByNameAsync(string roleName)
    {
        var result = await _roleManager.FindByNameAsync(roleName);
        if (result == null) return null;
        var PermissionDtos = GetPermissionDtos(result.RolePermissions);
        return new RoleDto(result.Id, result.Name!, result.NormalizedName!, PermissionDtos.ToList(), result.Description, result.Status, result.CreatedAt);
    }

    public async Task<IList<RoleDto>> GetAllRolesAsync()
    {
        var roles = _roleManager.Roles.Include(a => a.RolePermissions).ToList();

        return roles.Select(r => new RoleDto(r.Id, r.Name!, r.NormalizedName!, GetPermissionDtos(r.RolePermissions), r.Description, r.Status, r.CreatedAt)).ToList();
    }


    public async Task<OperationResult> DeleteRoleAsync(Guid roleId)
    {
        var role = await _roleManager.FindByIdAsync(roleId.ToString());
        if (role == null) return OperationResult.Failed("角色不存在");
        var result = await _roleManager.DeleteAsync(role);
        if (!result.Succeeded)
            return OperationResult.Failed(string.Join(",", result.Errors.Select(e => e.Description)));
        return OperationResult.Success();
    }

    public async Task<OperationResult> UpdateRoleNameAsync(Guid roleId, string newRoleName)
    {
        var role = await _roleManager.FindByIdAsync(roleId.ToString());
        if (role == null) return OperationResult.Failed("角色不存在");
        role.Name = newRoleName;
        var result = await _roleManager.UpdateAsync(role);
        if (!result.Succeeded)
            return OperationResult.Failed(string.Join(",", result.Errors.Select(e => e.Description)) ?? "角色修改失败");
        return OperationResult.Success();
    }

    public async Task<RoleDto?> SaveRoleAsync(Role role)
    {

        var approle = await _context.Roles.Include(rp => rp.RolePermissions).Where(r => r.Id == role.Id).FirstOrDefaultAsync();
        if (approle == null)
        {

            approle = new ApplicationRole { Id = role.Id, Name = role.Code, NormalizedName = role.Name, RolePermissions = new List<RolePermissionEntity>() };


            foreach (var permissionId in role.PermissionIds)
            {
                var permission = await _context.Permissions.Where(r => r.Id == permissionId).FirstOrDefaultAsync();
                if (permission == null) continue;
                approle.RolePermissions.Add(new RolePermissionEntity
                {
                    RoleId = approle.Id,
                    Role = approle,
                    PermissionId = permissionId,
                    Permission = permission

                });

            }

        }
        else
        {
            if (!string.IsNullOrWhiteSpace(role.Code) && approle.Name != role.Code) approle.Name = role.Code;
            if (string.IsNullOrWhiteSpace(approle.Name)) approle.Name = approle.NormalizedName;
            approle.NormalizedName = role.Name;
            approle.Description = role.Description;
            approle.Status = role.Status;

            
            var approlePermissionIds = approle.RolePermissions.Select(rp => rp.PermissionId);
            if (approlePermissionIds != role.PermissionIds)
            {
                var RolePermissionEntitys = _context.Permissions.Where(per => role.PermissionIds.Contains(per.Id)).Select(p => new RolePermissionEntity
                {
                    RoleId = approle.Id,
                    Role = approle,
                    PermissionId = p.Id,
                    Permission = p
                });
                approle.RolePermissions = RolePermissionEntitys.ToList();
            }

        }
        await _context.SaveChangesAsync();
        var PermissionDtos = GetPermissionDtos(approle.RolePermissions);
        return new RoleDto(approle.Id, approle.Name, approle.NormalizedName!, PermissionDtos.ToList(), approle.Description, approle.Status, approle.CreatedAt);

    }
    private List<PermissionDto> GetPermissionDtos(ICollection<RolePermissionEntity> rolePermissions)
    {
        var PermissionIds = rolePermissions.Select(p => p.PermissionId).ToHashSet();
        var BindingApiPermissionIds = _context.ApiPermissionBindings.Select(p => new { Id = p.permissionId, serviceName = p.FromServiceName });
        var PermissionDtos = from a in _context.Permissions.Where(p => PermissionIds.Contains(p.Id))
                             join b in BindingApiPermissionIds on a.Id equals b.Id into ab
                             from b in ab.DefaultIfEmpty()
                             select new PermissionDto(a.Id, a.Name, a.Key, a.Description, b != null ? b.serviceName : null, b != null);

        return PermissionDtos.ToList();
    }
}
